package com.wx.io.future;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.EventLoop;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.internal.StringUtil;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class FutureDemo {

    // 测试JDK-Future的方法
    public static void jdkFuture() throws Exception {
        System.out.println("--------JDK-Future测试--------");
        // 创建一个JDK线程池用于执行异步任务
        ExecutorService threadPool = Executors.newSingleThreadExecutor();

        System.out.println("主线程：步骤①");

        // 向线程池提交一个带有返回值的Callable任务
        java.util.concurrent.Future<String> task =
                threadPool.submit(() ->
                        "我是JDK-Future任务.....");
        // 输出获取到的任务执行结果（阻塞式获取）
        System.out.println(task.get());

        System.out.println("主线程：步骤②");
        // 关闭线程池
        threadPool.shutdownNow();
    }

    // 测试Netty-Future的方法
    public static void nettyFuture() {
        System.out.println("--------Netty-Future测试--------");
        // 创建一个Netty中的事件循环组（本质是线程池）
        NioEventLoopGroup group = new NioEventLoopGroup();
        EventLoop eventLoop = group.next();

        System.out.println("主线程：步骤①");

        // 向线程池中提交一个带有返回值的Callable任务
        io.netty.util.concurrent.Future<String> task =
                eventLoop.submit(() ->
                        "我是Netty-Future任务.....");

        // 添加一个异步任务执行完成之后的回调方法
        task.addListener(listenerTask ->
                System.out.println(listenerTask.getNow()));

        System.out.println("主线程：步骤②");
        // 关闭事件组（线程池）
        group.shutdownGracefully();
    }

    // 测试Netty-Promise的方法
    public static void nettyPromise() throws Exception {
        System.out.println("--------Netty-Promise测试--------");
        // 创建一个Netty中的事件循环组（本质是线程池）
        NioEventLoopGroup group = new NioEventLoopGroup();
        EventLoop eventLoop = group.next();

        // 主动创建一个传递异步任务结果的容器
        DefaultPromise<String> promise = new DefaultPromise<>(eventLoop);
        // 创建一条线程执行，往结果中添加数据
        new Thread(() -> {
            try {
                // 主动抛出一个异常
                int i = 100 / 0;
                // 如果异步任务执行成功，向容器中添加数据
                promise.setSuccess("我是Netty-Promise容器：执行成功！");
            } catch (Throwable throwable) {
                // 如果任务执行失败，将异常信息放入容器中
                promise.setFailure(throwable);
            }
        }).start();
        // 输出容器中的任务结果
        System.out.println(promise.get());
    }

    public static void main(String[] args) throws Exception {
        jdkFuture();
        nettyFuture();
        //nettyPromise();

        //String type = printNettyByteBufType();
        //System.out.println("Netty ByteBuf default Type :" + type);
        byteBufCapacityExpansion();

    }

    /**
     * 打印netty byte buf类型
     * class io.netty.buffer.PooledUnsafeDirectByteBuf
     *
     * @return {@link String}
     */
    private static String printNettyByteBufType() {
        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(1024 * 1024 * 100);
        return buffer.getClass().toString();
    }

    // 测试Netty-ByteBuf自动扩容机制
    private static void byteBufCapacityExpansion() {
        // 不指定默认容量大小为16
        ByteBuf buffer = ByteBufAllocator.DEFAULT.buffer(16);
        System.out.println("测试前的Buffer容量：" + buffer);
        // 使用StringBuffer来测试ByteBuf的自动扩容特性
        StringBuffer sb = new StringBuffer();
        // 往StringBuffer中插入17个字节的数据
        for (int i = 0; i < 17; i++) {
            sb.append("6");
        }
        // 将17个字节大小的数据写入缓冲区
        buffer.writeBytes(sb.toString().getBytes());
        printBuffer(buffer);
    }

    // 打印ByteBuf中数据的方法
    private static void printBuffer(ByteBuf buffer) {
        // 读取ByteBuffer已使用的字节数
        int byteSize = buffer.readableBytes();
        // 基于byteSize来计算显示的行数
        int rows = byteSize / 16 + (byteSize % 15 == 0 ? 0 : 1) + 4;
        // 创建一个StringBuilder用来显示输出
        StringBuilder sb = new StringBuilder(rows * 80 * 2);
        // 获取缓冲区的容量、读/写指针信息放入StringBuilder
        sb.append("ByteBuf缓冲区信息：{");
        sb.append("读取指针=").append(buffer.readerIndex()).append(", ");
        sb.append("写入指针=").append(buffer.writerIndex()).append(", ");
        sb.append("容量大小=").append(buffer.capacity()).append("}");

        // 利用Netty框架自带的格式化方法、Dump方法输出缓冲区数据
        sb.append(StringUtil.NEWLINE);
        ByteBufUtil.appendPrettyHexDump(sb, buffer);
        System.out.println(sb.toString());

    }
}
